
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <json-c/json.h>

#include <security/pam_modules.h>
#include <security/pam_ext.h>

#include "base64.h"
#include "sha512.h"
#include "debug.h"
#include "read_json_db.h"

#define DEFAULT_USER "nobody"

//in bytes
#define PASSWORD_SIZE    64
#define LOGIN_SIZE       64
#define SEED_SIZE        64
//in base64 size
#define PASSWORD64_SIZE  88
#define LOGIN64_SIZE     88
#define SEED64_SIZE      88


#define MSG_TYPE_USER 1
#define MSG_TYPE_SEED 2
#define MSG_TYPE_PWD  3


//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
			int argc, const char **argv)
{
	db_db *db=NULL;
	const char *name=NULL;
	const char *pass=NULL;
	const void *void_conv=NULL;
	const struct pam_conv *conv=NULL;
	char *data=NULL;
	int ret=-1;
	printf("pam_auth\n");
	pam_get_user( pamh, &name, NULL );
	pam_get_item( pamh, PAM_AUTHTOK, (const void **)&pass );
	ret = pam_get_data( pamh, "login", (const void **)&data );
	printf("pam_auth name = %s\n", data);

	pam_get_item( pamh, PAM_AUTHTOK, (const void **)&pass );
	printf("PAM_AUTHTOK = %s\n", pass);
	pam_get_item( pamh, PAM_USER, (const void **)&name );
	printf("PAM_USER=%s\n",name);

	ret = pam_get_item( pamh, PAM_CONV, &void_conv );
	conv = void_conv;
	if ( ret == PAM_SUCCESS )
	{
		db = open_json_db( "./conf/hausers.json" );
		if ( db==NULL ) ERROR("Cannot open db\n");
		db_user *user=NULL;
		get_user( db, name, &user );
		PRINT("asd\n");
		PRINT("[%s] [%s]\n", name, user->name );
		close_json_db( db );
		struct pam_message msg[1];
		const struct pam_message *pmsg[1];
		struct pam_response *resp=NULL;
		pmsg[0] = &msg[0];
		msg[0].msg_style = MSG_TYPE_SEED;
		char *str = new_string( user->seed );
		msg[0].msg = str;		
		ret = conv->conv( 1, pmsg, &resp, conv->appdata_ptr );
		//clear_user( user );
		if ( ret == PAM_SUCCESS )
		{
			PRINT("pam_auth\n");
			if (resp != NULL)
			{
				if (resp[0].resp != NULL)
				{
					char *pass = resp[0].resp;
					PRINT("pam_auth resp %s\n", pass);
				} else
				{
					ERROR("null response\n");
				}
			} else
			{
				ERROR("no response\n");
			}
		}
		FREE( str );
		pmsg[0] = &msg[0];
		msg[0].msg_style = MSG_TYPE_PWD;
		msg[0].msg = "password";
		ret = conv->conv( 1, pmsg, &resp, conv->appdata_ptr );
		if ( ret == PAM_SUCCESS )
		{
			PRINT("pam_auth\n");
			if (resp != NULL)
			{
				if (resp[0].resp != NULL)
				{
					char *pass = resp[0].resp;
					PRINT("pam_auth resp %s\n", pass);
				} else
				{
					ERROR("null response\n");
				}
			} else
			{
				ERROR("no response\n");
			}
		}
		if ( strncmp( user->password, resp[0].resp, PASSWORD64_SIZE ) != 0 )
		{
			PRINT("[%s]\n", user->password);
			PRINT("[%s]\n", resp[0].resp);
			ERROR("incorrect password\n");
			clean_user( user );
			return PAM_AUTH_ERR;
		}
		clean_user( user );
	} else
	{
		ERROR("pam_auth: canno get conv function\n");
		return PAM_AUTH_ERR;
	}

	return PAM_SUCCESS;
}


//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_setcred(pam_handle_t *pamh, int flags,
		   int argc, const char **argv)
{
	printf("set_cred\n");
    return PAM_SUCCESS;
}


/* --- account management functions --- */
//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
		     int argc, const char **argv)
{
	printf("sm_acct_mgmt\n");
    return PAM_SUCCESS;
}


/* --- password management --- */
//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
		     int argc, const char **argv)
{
	printf("sm_chauthtok\n");
	return PAM_SUCCESS;
}


/* --- session management --- */
//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_open_session(pam_handle_t *pamh, int flags,
			int argc, const char **argv)
{
	printf("sm_open_session\n");
    return PAM_SUCCESS;
}


//---------------------------------------------------------------------
PAM_EXTERN
int pam_sm_close_session(pam_handle_t *pamh, int flags,
			 int argc, const char **argv)
{
	printf("close_session\n");
    return PAM_SUCCESS;
}

/* end of module definition */

#ifdef PAM_STATIC

/* static module data */

struct pam_module _pam_debug_modstruct = {
    "pam_json",
    pam_sm_authenticate,
    pam_sm_setcred,
    pam_sm_acct_mgmt,
    pam_sm_open_session,
    pam_sm_close_session,
    pam_sm_chauthtok
};

#endif


